package com.nineclock.approve.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.resolver.ProcessNodeResolver;
import com.nineclock.approve.resolver.ProcessNodeResolverFactory;
import com.nineclock.approve.service.ActivitiService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 动态构建Activiti的 BpmnModel , 部署到Activiti
     * @param definition
     */
    @Override
    public void deployProcessToActiviti(ApproveDefinition definition) {
        //1. 构建BpmnModel
        BpmnModel bpmnModel = new BpmnModel();

        //1.1 构建Process对象
        Process process = new Process();
        process.setId("process_"+definition.getId());
        process.setName(definition.getName());

        //1.2 构建流程中的每个节点
        String flowJson = definition.getFlowJson();
        JSONArray flowArray = JSONUtil.parseArray(flowJson);
        addNodesToProcess(process, flowArray);

        bpmnModel.addProcess(process);


        //2. 将其部署到Activiti
        repositoryService.createDeployment()
                .name(definition.getName())
                .addBpmnModel(definition.getName()+".bpmn", bpmnModel)
                .deploy();

        //TODO --------> 用于测试;
        BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
        byte[] bytes = xmlConverter.convertToXML(bpmnModel);

        log.info("将动态构建出来的BpmnModel , 部署到Activiti完毕 ...");
        log.info("构建出来的BpmnModel ,对应XML格式数据为: ");
        log.info(new String(bytes));

    }



    @Override
    public void deleteProcessDeployFromActiviti(ApproveDefinition definition) {
        //获取流程定义key
        String key = "process_"+definition.getId();

        //根据流程定义key, 获取流程定义信息 ----> 获取到部署ID
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).singleResult();

        //删除
        if(processDefinition != null){
            repositoryService.deleteDeployment(processDefinition.getDeploymentId());
        }
    }




    /**
     * 遍历流程定义列表数据 , 将其解析并构建节点数据, 并将其添加到Process中;
     * @param process    流程对象
     * @param flowArray  流程数据 -----> json格式数组
     */
    private void addNodesToProcess(Process process, JSONArray flowArray) {
        //遍历流程数据---> json格式数组
        for (int i = 0; i < flowArray.size(); i++) {
            //获取每一个节点
            JSONObject currNode = (JSONObject) flowArray.get(i);
            //节点类型
            String type = currNode.getStr("type");// start, approval, CCList, end

            //获取下一个节点
            JSONObject nextNode= null;
            if(i < flowArray.size()-1){
                nextNode =  (JSONObject) flowArray.get(i+1);
            }

            //TODO -----> 需要根据节点的类型 , 使用不同的节点解析器, 动态构建当前节点类型对应的节点对象 StartEvent
            //1. 根据节点类型, 获取对应的节点处理器
            ProcessNodeResolver nodeResolver = ProcessNodeResolverFactory.getInstance(type);

            //2. 将当前节点, 构建节点对象, 添加Process流程中
            if(nodeResolver != null){
                nodeResolver.addFlowNodeToActiviti(process, currNode, nextNode);
            }

        }

    }

}
